﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace Gakita.Controller
{
    /* This controller handles the menu and highscore part of the game by dealing with user input 
       and switching between different menu screens */
    class MenuController : IController
    {
        public enum State
        {
            Main,
            SelectLevel,
            BestTimes,
            Options,
            KeyChangingMode
        }

        private MasterController.Controllers _nextController;
        private View.Menu.MenuView _menuView;
        private View.Menu.HighScoreModel _highscoreModel;
        private View.Menu.MainMenuModel _mainMenuModel                  =       new View.Menu.MainMenuModel();
        private View.Menu.SelectLevelModel _selectLevelModel            =       new View.Menu.SelectLevelModel();
        private View.Menu.OptionsMenuModel _optionsMenuModel            =       new View.Menu.OptionsMenuModel();
        private GraphicsDeviceManager _graphicsDeviceManager;

        private View.Menu.MenuModel _currentModel;
        private bool _changeController                                  =       false;
        private State _currentState                                     =       State.Main;
        private View.Menu.MenuModel.MenuOptions _currentKeyChange       =       View.Menu.MenuModel.MenuOptions.Nothing;

        public MenuController(GraphicsDeviceManager aGraphics, ContentManager aContentManager, SpriteBatch aSpriteBatch,                                                   View.Menu.HighScoreModel aHighScoreModel)
        {
            _menuView = new View.Menu.MenuView(aGraphics, aContentManager, aSpriteBatch);

            _currentModel = _mainMenuModel;
            _highscoreModel = aHighScoreModel;
            _graphicsDeviceManager = aGraphics;
        }

        /* This method draws either a menu, or the highscore page, depending on the controllers current state. 
           Which menu is drawn depends on what the current menumodel is */
        public void Draw(float aElapsedTime, GraphicsDevice aGraphics)
        {
            if (_currentState == State.Main || _currentState == State.Options || _currentState == State.KeyChangingMode ||
                _currentState == State.SelectLevel)
            {
                // Asks the current menu model for what menu options are available and which one is selected.
                // That info is then sent to the view so it can be drawn.
                View.Menu.MenuModel.MenuOptions[] MenuOptions = _currentModel.GetMenuOptions();
                View.Menu.MenuModel.MenuOptions SelectedMenuOption = _currentModel.GetSelectedMenuOption();

                bool GameIsRunning = Model.Model._gameIsRunning;

                _menuView.DrawMenu(MenuOptions, SelectedMenuOption, GameIsRunning, _currentKeyChange, 
                                   _highscoreModel.GetAllHighScores(),_currentState);
            }
            else if (_currentState == State.BestTimes)
            {
                _menuView.DrawHighScores(aGraphics, _highscoreModel.GetAllHighScores().ElementAt(_highscoreModel.GetActiveHighscore()),                                               _highscoreModel.GetActiveHighscore() + 1);
            }
            
        }

        public void Update(float aElapsedTime)
        {
            // If the user have choosen to rebind a key, the controller waits for input and then returns to the options state 
            // once the user have entered a new key.
            if (_currentState == State.KeyChangingMode)
            {
                if (_menuView.ChangeAKey(_currentKeyChange) == true)
                {
                    _currentKeyChange = View.Menu.MenuModel.MenuOptions.Nothing;
                    _currentState = State.Options;
                    return;
                }
                
            }
            // In the Main menu or Options menu, the user can switch which menu option is currently selected, and activate a menu option.
            else if (_currentState == State.Main || _currentState == State.Options || _currentState == State.SelectLevel)
            {
                View.Menu.MenuView.UserInput UserInput = _menuView.GetUserMenuInput();

                // Deal with user input
                if (UserInput == View.Menu.MenuView.UserInput.Nothing)
                {
                    return;
                }
                else if (UserInput == View.Menu.MenuView.UserInput.ChooseCurrent)
                {
                    switch (_currentModel.GetSelectedMenuOption())
                    {
                        case View.Menu.MenuModel.MenuOptions.NewGame:
                            {
                                SetNextController(MasterController.Controllers.Game);
                                _changeController = true;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.SelectLevel:
                            {
                                _currentState = State.SelectLevel;
                                _currentModel = _selectLevelModel;
                                _highscoreModel.LoadAllHighScores();
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.BestTimes:
                            {
                                _currentState = State.BestTimes;
                                _highscoreModel.LoadAllHighScores();
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.Options:
                            {
                                _currentState = State.Options;
                                _currentModel = _optionsMenuModel;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.ExitGame:
                            {
                                // The ExitGame menu option is used both in the main menu screen and the options screen.
                                // At the main menu, it exits the game, at the options screen it returns the user to the main menu.
                                if (_currentState == State.Main)
                                {
                                    _mainMenuModel.ExitProgram();
                                }
                                else
                                {
                                    _currentState = State.Main;
                                    _currentModel = _mainMenuModel;
                                }
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.FullScreen:
                            {
                                _graphicsDeviceManager.ToggleFullScreen();
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.JumpKey:
                            {
                                _currentKeyChange = View.Menu.MenuModel.MenuOptions.JumpKey;
                                _currentState = State.KeyChangingMode;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.LeftKey:
                            {
                                _currentKeyChange = View.Menu.MenuModel.MenuOptions.LeftKey;
                                _currentState = State.KeyChangingMode;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.RightKey:
                            {
                                _currentKeyChange = View.Menu.MenuModel.MenuOptions.RightKey;
                                _currentState = State.KeyChangingMode;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.FirstLevel:
                            {
                                Model.Model._isSelectLevelMode = true;
                                Model.Model._selectedLevel = Model.Level.Levels.first;
                                Model.Model._isSelectLevelModeStarted = false;
                                SetNextController(MasterController.Controllers.Game);
                                _changeController = true;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.SecondLevel:
                            {
                                Model.Model._isSelectLevelMode = true;
                                Model.Model._selectedLevel = Model.Level.Levels.second;
                                Model.Model._isSelectLevelModeStarted = false;
                                SetNextController(MasterController.Controllers.Game);
                                _changeController = true;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.ThirdLevel:
                            {
                                Model.Model._isSelectLevelMode = true;
                                Model.Model._selectedLevel = Model.Level.Levels.third;
                                Model.Model._isSelectLevelModeStarted = false;
                                SetNextController(MasterController.Controllers.Game);
                                _changeController = true;
                                break;
                            }
                        case View.Menu.MenuModel.MenuOptions.FourthLevel:
                            {
                                Model.Model._isSelectLevelMode = true;
                                Model.Model._selectedLevel = Model.Level.Levels.fourth;
                                Model.Model._isSelectLevelModeStarted = false;
                                SetNextController(MasterController.Controllers.Game);
                                _changeController = true;
                                break;
                            }

                    }
                }
                else if (UserInput == View.Menu.MenuView.UserInput.ChangeUp)
                {
                    _currentModel.SelectPreviousMenuOption();
                }
                else if (UserInput == View.Menu.MenuView.UserInput.ChangeDown)
                {
                    _currentModel.SelectNextMenuOption();
                }
            }
            // At the highscore screen, the user can switch which level he is viewing highscores for, and also return to the main menu.
            else if (_currentState == State.BestTimes)
            {
                View.Menu.MenuView.UserInput UserInput = _menuView.GetUserHighScoreInput();

                // Deal with user input
                switch (UserInput)
                {
                    case View.Menu.MenuView.UserInput.GoNextHighScore:
                        _highscoreModel.NextActiveHighScore();
                        break;
                    case View.Menu.MenuView.UserInput.GoPreviousHighScore:
                        _highscoreModel.PreviousActiveHighScore();
                        break;
                    case View.Menu.MenuView.UserInput.Back:
                        _currentState = State.Main;
                        break;
                    default:
                        return;
                }
            }

        }

        /* This method checks if the controller needs to be changed */
        public bool DidUserChangeController()
        {
            bool ret = _changeController;
            _changeController = false;
            return ret;
        }

        public void SetNextController(MasterController.Controllers aController)
        {
            _nextController = aController;
        }

        public MasterController.Controllers ControllerToChangeTo()
        {
            return _nextController;
        }

    }
}